package org.farm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.farm.Enum.ResultCodeEnum;
import org.farm.dto.LoginDTO;
import org.farm.dto.RegisterDTO;
import org.farm.mapper.SysLogLoginMapper;
import org.farm.mapper.SysLogOperationMapper;
import org.farm.mapper.SysUserMapper;
import org.farm.mapper.SysUserTokenMapper;
import org.farm.pojo.*;
import org.farm.service.SysUserService;
import org.farm.utils.CacheManager;
import org.farm.utils.TokenUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class SysUserServiceImpl implements SysUserService {
    private static final Logger logger = LoggerFactory.getLogger(SysUserServiceImpl.class);

    @Autowired
    private SysUserMapper userMapper;
    @Autowired
    private SysUserTokenMapper tokenMapper;
    @Autowired
    private SysLogLoginMapper logLoginMapper;
    @Autowired
    private SysLogOperationMapper logOperationMapper;
    @Autowired
    private TokenUtils tokenUtils;
    @Autowired
    private CacheManager cacheManager;
    private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultVo<Map<String, Object>> login(LoginDTO loginDTO) {
        logger.debug("开始登录流程，用户: {}", loginDTO.getUsername());

        SysUser user = cacheManager.getUserFromCache(loginDTO.getUsername(), this);
        if (user == null) {
            user = getUserByUsername(loginDTO.getUsername());
            if (user == null) {
                logger.warn("登录失败，用户不存在: {}", loginDTO.getUsername());
                return ResultVo.fails(ResultCodeEnum.ACCOUNT_ERROR, "用户不存在");
            }
        }

        if (!passwordEncoder.matches(loginDTO.getPassword(), user.getPassword())) {
            logger.warn("登录失败，密码错误: {}", loginDTO.getUsername());
            recordLoginLog(user, 0, 0);
            return ResultVo.fails(ResultCodeEnum.PASSWORD_ERROR, "密码错误");
        }

        if (user.getStatus() == 0) {
            logger.warn("登录失败，账户已禁用: {}", loginDTO.getUsername());
            recordLoginLog(user, 0, 2);
            return ResultVo.fails(ResultCodeEnum.ACCOUNT_STOP, "账户已禁用");
        }

        String token = tokenUtils.generateToken(user.getId());
        SysUserToken userToken = new SysUserToken();
        userToken.setUserId(user.getId());
        userToken.setToken(token);
        userToken.setExpireDate(new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000));
        userToken.setCreateDate(new Date());
        userToken.setUpdateDate(new Date());
        tokenMapper.insert(userToken);

        recordLoginLog(user, 0, 1);
        logger.info("用户登录成功: {}", loginDTO.getUsername());

        Map<String, Object> resultData = new HashMap<>();
        resultData.put("token", token);
//        resultData.put("user", user);
        return ResultVo.success(resultData);
    }

    @Override
    @Transactional
    public void logout(String token) {
        logger.debug("开始登出流程，Token: {}", token);
        SysUserToken userToken = cacheManager.getTokenFromCache(token, this);
        if (userToken != null) {
            SysUser user = getUserByUsername(userMapper.selectById(userToken.getUserId()).getUsername());
            tokenMapper.delete(new LambdaQueryWrapper<SysUserToken>().eq(SysUserToken::getToken, token));
            cacheManager.invalidateTokenCache(token);
            recordLoginLog(user, 1, 1);
            logger.info("用户登出成功: {}", user.getUsername());
        } else {
            logger.warn("登出失败，Token不存在: {}", token);
        }
    }

    @Override
    public SysUser getUserByUsername(String username) {
        logger.debug("查询用户: {}", username);
        return userMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username));
    }

    @Override
    public SysUserToken getTokenByToken(String token) {
        logger.debug("查询Token: {}", token);
        return tokenMapper.selectOne(new LambdaQueryWrapper<SysUserToken>().eq(SysUserToken::getToken, token));
    }

    @Override
    @Transactional
    public void register(RegisterDTO registerDTO) {
        logger.debug("开始注册流程，用户: {}", registerDTO.getUsername());

        // 检查用户名是否已存在
        SysUser existingUser = cacheManager.getUserFromCache(registerDTO.getUsername(), this);
        if (existingUser != null) {
            logger.warn("注册失败，用户名已存在: {}", registerDTO.getUsername());
            throw new RuntimeException("用户名已存在");
        }

        // 额外查询数据库确认
        existingUser = getUserByUsername(registerDTO.getUsername());
        if (existingUser != null) {
            logger.warn("注册失败，用户名已存在: {}", registerDTO.getUsername());
            throw new RuntimeException("用户名已存在");
        }

        // 创建新用户
        SysUser newUser = new SysUser();
        newUser.setUsername(registerDTO.getUsername());
        newUser.setPassword(passwordEncoder.encode(registerDTO.getPassword()));
        newUser.setRealName(registerDTO.getRealName());
        newUser.setEmail(registerDTO.getEmail());
        newUser.setMobile(registerDTO.getMobile());

        // 处理性别
        Character genderChar = registerDTO.getGender();
        if (genderChar != null) {
            if (genderChar == '男' || genderChar == '女') {
                newUser.setGender(genderChar);
            } else {
                logger.warn("无效的性别输入: {}，设置为默认值 null", genderChar);
                newUser.setGender(null); // 默认值设为 null
            }
        } else {
            newUser.setGender(null); // 默认值设为 null
        }

        newUser.setUserType(1); // 默认用户权限
        newUser.setFarmId(registerDTO.getFarmId());
        newUser.setPosition(registerDTO.getPosition());
        newUser.setStatus(1);   // 默认正常状态
        newUser.setCreator(0L); // 系统创建
        newUser.setCreateDate(new Date());
        newUser.setUpdater(0L);
        newUser.setUpdateDate(new Date());

        logger.debug("准备插入新用户: {}", newUser.getUsername());
        int result = userMapper.insert(newUser);
        if (result > 0) {
            logger.debug("用户插入成功，更新缓存: {}", registerDTO.getUsername());
            cacheManager.invalidateUserCache(registerDTO.getUsername());
            logger.info("用户注册成功: {}", registerDTO.getUsername());
            recordOperationLog(newUser, "用户注册", "/auth/register", "POST", 1);
        } else {
            logger.error("用户注册失败，插入记录数为0: {}", registerDTO.getUsername());
            recordOperationLog(newUser, "用户注册", "/auth/register", "POST", 0);
            throw new RuntimeException("注册失败");
        }
    }

    private void recordLoginLog(SysUser user, int operation, int status) {
        SysLogLogin log = new SysLogLogin();
        log.setOperation(operation);
        log.setStatus(status);
        log.setUserAgent(getUserAgent());
        log.setIp(getIp());
        log.setCreatorName(user.getUsername());
        log.setCreator(user.getId());
        log.setCreateDate(new Date());
        logLoginMapper.insert(log);
    }

    private void recordOperationLog(SysUser user, String operation, String uri, String method, int status) {
        SysLogOperation log = new SysLogOperation();
        log.setOperation(operation);
        log.setRequestUri(uri);
        log.setRequestMethod(method);
        log.setRequestParams(user.toString());
        log.setRequestTime((int) (System.currentTimeMillis() % 1000));
        log.setUserAgent(getUserAgent());
        log.setIp(getIp());
        log.setStatus(status);
        log.setCreatorName(user.getUsername());
        log.setCreator(user.getId());
        log.setCreateDate(new Date());
        logOperationMapper.insert(log);
    }

    private String getUserAgent() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            return request.getHeader("User-Agent") != null ? request.getHeader("User-Agent") : "Unknown";
        }
        return "Unknown";
    }

    private String getIp() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            String ip = request.getHeader("X-Forwarded-For");
            if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
            return ip;
        }
        return "Unknown";
    }
}